package com.github.xzb617.rpc.httpclient;

import com.github.xzb617.rpc.core.AbstractRequestCaller;
import com.github.xzb617.rpc.entity.RpcConfig;
import com.github.xzb617.rpc.entity.Server;
import com.sun.org.apache.regexp.internal.RE;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.utils.URLEncodedUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestClientException;
import sun.nio.ch.IOUtil;

import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.Map;

/**
 * 基于HttpClient的请求
 */
public class HttpClientRequestCaller extends AbstractRequestCaller {

    private final static int DEFAULT_TIMEOUT = 100000;
    private final static String DEFAULT_ENCODE = "UTF-8";

    private Integer timeout;
    private String encode;
    private Header[] headers;

    public HttpClientRequestCaller(RpcConfig rpcConfig) {
        super(rpcConfig);
        this.headers = HttpClientUtil.buildHeaders(rpcConfig.getHeaders());
        this.timeout = timeout==null ? DEFAULT_TIMEOUT : timeout;
        this.encode  = encode==null ? DEFAULT_ENCODE : encode;
    }


    @Override
    public <T> ResponseEntity<T> get(Server server, String methodPath, Map<String, String> parameters, Map<String, String> headers, Class<T> responseType) {
        // 构建API地址
        String url = server.getAddress() + methodPath;
        // 使用连接池
        HttpClient httpClient = HttpClientUtil.getInstance();
        HttpGet httpGet = new HttpGet();
        httpGet.setConfig(HttpClientUtil.buildRequestConfig(this.timeout, this.timeout));
        String strParameters = URLEncodedUtils.format(HttpClientUtil.buildNameValuePair(parameters), this.encode);
        httpGet.setURI(URI.create(url + "?" + strParameters));
        // 添加请求头
        Header[] httpHeaders = HttpClientUtil.buildHeaders(headers);
        httpGet.setHeaders(httpHeaders);
        // 执行请求，并包装响应结果
        try {
            HttpResponse response = httpClient.execute(httpGet);
            return HttpClientUtil.toResponseEntity(response, responseType);
        }
        catch (IOException e) {
            throw new RestClientException("Failed to send get request to config server， cause by: " + e.getMessage());
        }
        finally {
            // 释放连接
            httpGet.releaseConnection();
        }
    }

    @Override
    public <T> ResponseEntity<T> post(Server server, String methodPath, Map<String, String> parameters, Map<String, String> headers, Class<T> responseType) {
        // 构建API地址
        String url = server.getAddress() + methodPath;
        // 使用连接池
        HttpClient httpClient = HttpClientUtil.getInstance();
        HttpPost httpPost = new HttpPost(url);
        RequestConfig requestConfig = HttpClientUtil.buildRequestConfig(this.timeout, this.timeout);
        httpPost.setConfig(requestConfig);
        // 添加请求头
        Header[] httpHeaders = HttpClientUtil.buildHeaders(headers);
        httpPost.setHeaders(httpHeaders);
        List<NameValuePair> nameValuePairs = HttpClientUtil.buildNameValuePair(parameters);
        try {
            UrlEncodedFormEntity formParameters = new UrlEncodedFormEntity(nameValuePairs, this.encode);
            httpPost.setEntity(formParameters);
            HttpResponse response = httpClient.execute(httpPost);
            return HttpClientUtil.toResponseEntity(response, responseType);
        }
        catch (IOException e) {
            throw new RestClientException("Failed to send post request to config server, cause by: " + e.getMessage());
        }
        finally {
            httpPost.releaseConnection();
        }
    }

    @Override
    public <T> ResponseEntity<T> put(Server server, String methodPath, Map<String, String> parameters, Map<String, String> headers, Class<T> responseType) {
        // 构建API地址
        String url = server.getAddress() + methodPath;
        // 使用连接池
        HttpClient httpClient = HttpClientUtil.getInstance();
        HttpPut httpPut = new HttpPut(url);
        RequestConfig requestConfig = HttpClientUtil.buildRequestConfig(this.timeout, this.timeout);
        httpPut.setConfig(requestConfig);
        // 添加请求头
        Header[] httpHeaders = HttpClientUtil.buildHeaders(headers);
        httpPut.setHeaders(httpHeaders);
        List<NameValuePair> nameValuePairs = HttpClientUtil.buildNameValuePair(parameters);
        try {
            UrlEncodedFormEntity formParameters = new UrlEncodedFormEntity(nameValuePairs, this.encode);
            httpPut.setEntity(formParameters);
            HttpResponse response = httpClient.execute(httpPut);
            return HttpClientUtil.toResponseEntity(response, responseType);
        }
        catch (IOException e) {
            throw new RestClientException("Failed to send put request to config server, cause by: " + e.getMessage());
        }
        finally {
            httpPut.releaseConnection();
        }
    }

    @Override
    public <T> ResponseEntity<T> delete(Server server, String methodPath, Map<String, String> parameters, Map<String, String> headers, Class<T> responseType) {
        // 构建API地址
        String url = server.getAddress() + methodPath;
        // 使用连接池
        HttpClient httpClient = HttpClientUtil.getInstance();
        HttpDelete httpDelete = new HttpDelete();
        httpDelete.setConfig(HttpClientUtil.buildRequestConfig(this.timeout, this.timeout));
        String strParameters = URLEncodedUtils.format(HttpClientUtil.buildNameValuePair(parameters), this.encode);
        httpDelete.setURI(URI.create(url + "?" + strParameters));
        // 添加请求头
        Header[] httpHeaders = HttpClientUtil.buildHeaders(headers);
        httpDelete.setHeaders(httpHeaders);
        // 执行请求，并包装响应结果
        try {
            HttpResponse response = httpClient.execute(httpDelete);
            return HttpClientUtil.toResponseEntity(response, responseType);
        }
        catch (IOException e) {
            throw new RestClientException("Failed to send get request to config server， cause by: " + e.getMessage());
        }
        finally {
            // 释放连接
            httpDelete.releaseConnection();
        }
    }
}
